#from tagfs import TagFSPath
from tagfs import *
from localfs import LocalFileSystem
from localfs import LocalFile
from fs import *
from threading import Lock
import fs
import sqlite3
import random
import os, os.path, glob

class SimpleTagFile(TagFile):
    def __init__(self, fileobj, id):
        self.fileid = id
        self.file = fileobj
    
    def seek(self, offset, whence = os.SEEK_SET):
        self.file.seek(offset, whence)
    
    def read(self, size = -1):
        return self.file.read(size)
    
    def write(self, buf, size = -1):
        self.file.write(buf, size)
     
    def open(self, mode = ACCESS_RW):
        self.file.open(mode)
    

    def tell(self):
        return self.file.tell()
    
    def close(self):
        self.file.close()
    
    def size(self):
        return self.file.size()
    
    def description(self):
        return ""
    
    def path(self):
        return self.fileid

class SimpleTagFS(TagFS):
    dbdir = "/dbfile"
    dbfile = dbdir + "/tagfs.db"
    
    #
    tanknumber = 256
    tankcapacity = 1024
    
    
    def __init__(self, baseFS):
        self.basefs = baseFS
        verify = self.verifyFS()
        if verify == INTEGRITY_BROKEN:
            self.repairFS()
        elif verify == INTEGRITY_NOT_EXIST:
            self.initFS()
            
        self.dblock = Lock()
                                
    
    def getDBConnection(self): #override this to use other db system
        realpath = self.basefs.realpath(SimpleTagFS.dbfile)
        conn = sqlite3.connect(realpath)
        return conn
    
    def verifyFS(self):
        return self.verifyDB()
    
    def verifyDB(self):
        allgood = True
        anygood = False
        # db dir exist ?
        direxist = self.basefs.exists(SimpleTagFS.dbdir) and self.basefs.isDirectory(SimpleTagFS.dbdir)
        allgood &= direxist
        anygood |= direxist
        
        if anygood == False:
            return INTEGRITY_NOT_EXIST
        elif allgood == True:
            return INTEGRITY_OK
        else:
            return INTEGRITY_BROKEN
        
    
    def initFS(self):
        print("initial a FS")
        self.basefs.mkdir(SimpleTagFS.dbdir)
        conn = self.getDBConnection()
        c = conn.cursor()
        #store
        c.execute("create table store (id INTEGER PRIMARY KEY, name TEXT, repo INTEGER)")
        c.execute("create index store_repo on store(repo asc)")
        #detail
        c.execute("create table detail (id INTEGER, descript TEXT)")
        #tag
        c.execute("create table tag (id INTEGER PRIMARY KEY, name TEXT, count INTEGER)")
        c.execute("create index tag_count on tag(count desc)")
        #filetag
        c.execute("create table filetag (fileid INTEGER, tagid INTEGER)")
        c.execute("create index filetag_fid on filetag(fileid asc)")
        c.execute("create index filetag_tid on filetag(tagid asc)")
        conn.commit()
        c.close()
        conn.close()
        
    
    def repairFS(self):
        print("repair a FS")
        
    def create(self, path):
        """
        Return a file at path, not open.
        """
        if isinstance(path, str):
            created = self.createNamedFile(path)
        else:
            assert path.filename != None and path.filename != ""
            created = self.createNamedFile(path.filename)
            #todo
        return created
        
    def createNamedFile(self, filename):
        tankid = random.randint(0, SimpleTagFS.tanknumber - 1)
        
        with self.dblock:
            while True:
                tankstr = str(tankid)
                if not self.basefs.exists(tankstr):
                    self.basefs.mkdir(tankstr)
                if self.basefs.exists(tankstr + "/" + filename) or len(self.basefs.listpath(tankstr)) >= SimpleTagFS.tankcapacity:
                    tankid += SimpleTagFS.tanknumber
                    continue
                created = self.basefs.create(tankstr + "/" + filename)
                break
            fileid = self.insertFile(filename, tankid)
        #return created
        tagfile = SimpleTagFile(created, fileid)
        return tagfile
    
    def insertFile(self, name, tank):
        #inssql = "insert into store values (NULL, '%s', %d)" % (name, tank)
        inssql = "insert into store values (NULL, ?, ?)"
        qidsql  = "select last_insert_rowid() from store limit 1"
        conn = self.getDBConnection()
        c = conn.cursor()
        #c.execute(inssql)
        v = (name, tank)
        c.execute(inssql, v)
        conn.commit()
        c.execute(qidsql)
        for row in c:
            id = row[0]
        c.close()
        conn.close()
        return id
        
        
    
    def open(self, path):
        assert isinstance(path, int)
        name, repo = self.queryfile(path)
        if name == None or repo == None:
            raise IOError("No such file.")
        basefile = self.basefs.open(str(repo) + "/" + name)
        tagfile = SimpleTagFile(basefile, path)
        return tagfile
        
    def queryfile(self, fileid):
        qidsql = "select name, repo from store where id = ?"
        conn = self.getDBConnection()
        c = conn.cursor()
        c.execute(qidsql, (fileid,))
        name = None
        repo = None
        for row in c:
            name, repo = row
        c.close()
        conn.close()
        return name, repo
    
    def delete(self, path):
        pass
    
    def exists(self, path):
        return False
    
    def find(self, namepatten, inpath = None):
        return [] 